﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.IO;
using System.Net;
using DownloadApi.Net;

namespace AppBrowser
{
    public partial class frmDownloadApps : Form
    {
        private DownloadManager DLManager;

        /// <summary>
        /// Applications that have been checked, to prepare for download
        /// </summary>
        private List<AppItem> _AppList = new List<AppItem>();
        public List<AppItem> AppList
        {
            get { return _AppList;  }
            set { _AppList = value; }
        }

        public frmDownloadApps()
        {
            InitializeComponent();
        }



        /// <summary>
        /// Build List from SelectedAppsList
        /// </summary>
        public void buildListView()
        {
            listView1.Items.Clear();
            
            // set width for last item
            int width = 0; int cnt=0;
            for (int i = 0; i < listView1.Columns.Count - 1; i++)
            {
                width += listView1.Columns[i].Width;
                cnt++;
            }

            listView1.Columns[cnt].Width = listView1.Width - width;

            // loop through list and prepare listview
            foreach (AppItem appData in _AppList)
            {               
                ListViewItem li = new ListViewItem(appData.AppName);
                AppVersion appVer = appData.GetSelectedVersion();
                string filepath = "";
                string downloadurl = "";
                string versionStr="";
                string filesize = "0";
                string versionType = "";

                if (appVer != null)
                {
                    versionStr = appVer.VersionNumber;
                    downloadurl=appVer.DownloadUrl;
                    versionType = appVer.VersionType;
                    // Generate filepath
                    filepath = BuildFilePath(appData);

                    // get live filesize from external sites
                    // filesize = DownloadTools.GetFileSize(downloadurl).ToString();
                }

                // now add array of items
                // change this if changing column display order
                li.SubItems.AddRange(new string[] { versionStr, versionType, "-", filepath });
                li.Tag = appData;
                li.ToolTipText = downloadurl;               
                listView1.Items.Add(li);
            }
            
        }

        /// <summary>
        /// Build filepath to download to
        /// </summary>
        /// <returns></returns>
        public string BuildFilePath(AppItem app)
        {
            string tmpStr;
            string DownloadString= txtDownloadString.Text;

            if (DownloadString == "")
            {
                try
                {
                    DownloadString = Properties.Settings.Default.DownloadString;
                }
                catch
                {
                    DownloadString = "[AppName]\\[AppVersion]\\[AppFileName]";
                }
            }   
            string ValidChars = @"[?:\/*""<>|]";
            string tFile = Regex.Replace(app.AppName, ValidChars, "");
            tmpStr = DownloadString.Replace("[Publisher]", Regex.Replace(app.Publisher, ValidChars,""));
            tmpStr = tmpStr.Replace("[AppName]", Regex.Replace(app.AppName,ValidChars,""));

            // Replace date if needed
            tmpStr = tmpStr.Replace("[DateNow]", DateTime.Now.ToString("yyyyMMdd"));


            string AppFileName="";
            string VersionDir = "";

            // get Version
            AppVersion appVersion = app.GetSelectedVersion();
            if (appVersion != null)
            {
                // determine filename
                if (appVersion.FileName != null && appVersion.FileName!="")
                {
                    AppFileName = appVersion.FileName;
                }
                else
                {
                    AppFileName = appVersion.GetFileNameFromUrl();
                }

                VersionDir = "V_" + appVersion.ToString().Replace('.', '_');
            }

            tmpStr = tmpStr.Replace("[AppVersion]", Regex.Replace(VersionDir, ValidChars, ""));
            tmpStr = tmpStr.Replace("[AppFileName]", AppFileName);
            tmpStr = tmpStr.Replace("[AppFileNoExt]", Path.GetFileNameWithoutExtension(AppFileName));
            tmpStr = tmpStr.Replace("[AppFileExt]", Path.GetExtension(AppFileName));

            
            return tmpStr;
        }
     
        private void frmDownloadApps_Load(object sender, EventArgs e)
        {
            btnCancel.Enabled = false;

            // set download base path from config
            txtDownloadPath.Text = Properties.Settings.Default.DownloadsPath;

            // num threads
            txtDownloadString.Text = Properties.Settings.Default.DownloadString;
            txtNumThreads.Text = Properties.Settings.Default.DownloadThreads.ToString();
           

            // check if directory exists
            if (!Directory.Exists(txtDownloadPath.Text))
            {
                if (MessageBox.Show("The directory \"" + txtDownloadPath.Text +
                    "\" does not exist, would you like to select another directory",
                    "Choose another Directory", MessageBoxButtons.YesNoCancel) == DialogResult.Yes)
                {
                    browsePath_Click(sender, e);

                }
            }


            buildListView();
            DLManager = new DownloadManager(this, 2, BuildItemListFromAppList()); 
            
          
        }

        public void SetAppsList(List<AppItem> apps)
        {
            this._AppList = apps;
        }

        private void btnStartCancel_Click(object sender, EventArgs e)
        {
            if (btnStart.Text == "Start")
            {
                if (AppList.Count > 0)
                {
                    if (Directory.Exists(txtDownloadPath.Text))
                    {
                        // Check Number of threads
                        if (txtNumThreads.Text != "")
                        {
                            DLManager.NumThreads = Convert.ToInt16(txtNumThreads.Text);
                        }
                        // start the worker process
                        DLManager.BaseDownloadPath = txtDownloadPath.Text;

                        toolStripStatusLabel1.Text = "Starting Download Process "
                                    + AppList.Count + " Files / "
                                    + DLManager.NumThreads + " Threads";
                                     
                        
                        DLManager.LaunchManagedProcess();
                    }
                    else
                    {
                        MessageBox.Show("Sorry directory \""+txtDownloadPath.Text+"\" does not exist");
                        browsePath_Click(sender, e);
                    }
                }
            }
            else
            {
                // currently processing
            }
        }

        private DownloadItem[] BuildItemListFromAppList()
        {
            DownloadItem[] dlList = new DownloadItem[_AppList.Count];
            int counter=-1;
            foreach (AppItem ai in _AppList)
            {
                AppVersion ver = ai.GetSelectedVersion();
                counter++;
                dlList[counter] = new DownloadItem();
              
                dlList[counter].FilePath = BuildFilePath(ai);
                dlList[counter].StartPoint = 0;

                // Add Version Info
                if (ver != null)
                {
                    dlList[counter].DownloadUrl = ver.DownloadUrl;
                }
            }
            return dlList;
        }

        private void copyURLToClipboardToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (listView1.SelectedItems.Count > 0)
            {
                // Get URL data
                AppItem app = (AppItem)listView1.SelectedItems[0].Tag;
                string url = app.GetSelectedVersion().DownloadUrl;

                System.Windows.Forms.Clipboard.SetDataObject(url, true); 
            }
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            toolStripStatusLabel1.Text = "Download Process Cancelled";
            DLManager.StopManagedProcess();           
        }

        private void browsePath_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog fb = new FolderBrowserDialog();
            fb.SelectedPath = txtDownloadPath.Text;
            if (fb.ShowDialog() == DialogResult.OK)
            {
                txtDownloadPath.Text = fb.SelectedPath;

                // Save to Properties.Settings.Default
                Properties.Settings.Default.DownloadsPath = txtDownloadPath.Text;
                Properties.Settings.Default.Save();
            }
        }

        private void openFolderInExplorerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (listView1.SelectedItems.Count > 0)
            {
                string folder = listView1.SelectedItems[0].SubItems[3].Text;
                folder = Path.GetDirectoryName(txtDownloadPath.Text + "\\" + folder);

                if (Directory.Exists(folder))
                {
                    System.Diagnostics.Process.Start(folder);
                }
                else
                {
                    MessageBox.Show("Folder \"" + folder + "\" does not currently exist\r\n Once download process starts this folder will be created.");
                }
            }
        }

        private void btnOpenDownloads_Click(object sender, EventArgs e)
        {
            
            if (Directory.Exists(txtDownloadPath.Text))
            {
                System.Diagnostics.Process.Start(txtDownloadPath.Text);
            }
            else
            {
                MessageBox.Show("Folder \"" + txtDownloadPath.Text + "\" does not currently exist\r\n Once download process starts this folder will be created.");
            }

        }

        private void btnShowDownloadHelp_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Download Format String: \r\n"
                + "\r\n[Publisher]        - Application Publisher"
                + "\r\n[AppName]          - Application Name"
                + "\r\n[AppVersion]       - Version"
                + "\r\n[DateNow]          - Current Date in yyyyMMdd format"
                + "\r\n[AppFileName]      - Application Filename (with extension)"
                + "\r\n[AppFileNoExt]     - Filename without extension"
                + "\r\n[AppFileExt]       - Extension of filename"
                + "\r\n\r\nExample:\r\n\t[Publisher]\\[AppName]\\[AppVersion]\\[AppFileName]\r\n"
                + "\t\"mypublisher\\myapp\\v_203\\appinstall.exe\""
                + "\r\n\r\n\t[AppName]\\[AppFileNoExt]_[AppVersion][AppFileExt]\r\n"
                + "\t\"myapp\\appinstall_v_203.exe\""
                );
        }

        private void btnRefreshForm_Click(object sender, EventArgs e)
        {
            buildListView();
        }

        /// <summary>
        /// Call from manager to indicate all downloads completed
        /// </summary>
        public void AllDownloadsCompleted()
        {

        }

        private void btnResetDownloadString_Click(object sender, EventArgs e)
        {
            Properties.Settings.Default.DownloadString = Properties.Settings.Default.Default_DownloadString;
            txtDownloadString.Text = Properties.Settings.Default.DownloadString;

            btnRefreshForm_Click(sender,  e);
        }

        private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
        {
            if (listView1.SelectedItems.Count > 0)
            {
                contextMenuStrip1.Enabled = true;
            }
            else
            {
                contextMenuStrip1.Enabled = false;
            }
        }

        private void btnToggleAdvanced_Click(object sender, EventArgs e)
        {
            if (btnToggleAdvanced.Text == "Less")
            {
                btnToggleAdvanced.Text = "Advanced";
                panelAdvanced.Enabled = false;
                panelAdvanced.Visible = false;
            }
            else
            {
                btnToggleAdvanced.Text = "Less";
                panelAdvanced.Enabled = true;
                panelAdvanced.Visible = true;
            }
        }

        private void listView1_MouseHover(object sender, EventArgs e)
        {
            if (listView1.SelectedItems.Count > 0)
            {
                AppItem app = (AppItem)listView1.SelectedItems[0].Tag;

            }
        }

        private void listView1_SizeChanged(object sender, EventArgs e)
        {
            // set width for last item
            int width = 0; int cnt = 0;
            for (int i = 0; i < listView1.Columns.Count - 1; i++)
            {
                width += listView1.Columns[i].Width;
                cnt++;
            }

            listView1.Columns[cnt].Width = listView1.Width - width;

        }

        bool nonNumberEntered;
        private void txtNumThreads_KeyPress(object sender, KeyPressEventArgs e)
        {
            // Check for the flag being set in the KeyDown event.
            if (nonNumberEntered == true)
            {
                // Stop the character from being entered into the control since it is non-numerical.
                e.Handled = true;
            }            
        }

        private void txtNumThreads_KeyDown(object sender, KeyEventArgs e)
        {
            // ignore any non numeric input
            // Initialize the flag to false.
            nonNumberEntered = false;

            // Determine whether the keystroke is a number from the top of the keyboard.
            if (e.KeyCode < Keys.D0 || e.KeyCode > Keys.D9)
            {
                // Determine whether the keystroke is a number from the keypad.
                if (e.KeyCode < Keys.NumPad0 || e.KeyCode > Keys.NumPad9)
                {
                    // Determine whether the keystroke is a backspace.
                    if (e.KeyCode != Keys.Back)
                    {
                        // A non-numerical keystroke was pressed.
                        // Set the flag to true and evaluate in KeyPress event.
                        nonNumberEntered = true;
                    }
                }
            }
        }

    }
}
